#include <sys/types.h> 
#include <sys/stat.h> 
#include <string.h> 
#include <stdio.h> 
#include <fcntl.h> 
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/types.h>
#include "cetc14-iic.h"

int higher2lower(char c);
int htoi(char s[]);


#define L0_CSR(port,destID) (0x318000 + 0x20000 * port + 0x4 * destID)
#define L1_CSR(port,group,destID) (0x318400 + 0x20000 * port + 0x400 * group + 0x4 * destID)
#define L2_CSR(port,group,destID) (0x319000 + 0x20000 * port + 0x400 * group + 0x4 * destID)
#define MC_S_CSR(port,destID) (0x31C000 + 0x20000 * port + 0x8 *destID)
#define MC_CSR(port,destID) (0x31C004 + 0x20000 * port + 0x8 * destID)

int main(int argc, char *argv[]) 
{
	unsigned int tempval,tempval1;
	int i,count;
	
	unsigned int port, level, group, value;

	unsigned int reg_address[256] = {0};
	unsigned int destid_array[256] = {0};
	unsigned int sdi_index;

	count = 0;
	tempval = 0;
	tempval1 = 0;
	port = htoi(argv[1]);
	level = htoi(argv[2]);
	group = htoi(argv[3]);
	value = htoi(argv[4]);
	sdi_index=htoi(argv[5]);

	if(level == 0)
	{
		for(i = 0;i < 256;i++)
		{
			iic_access(sdi_index,0x58,L0_CSR(port,i),&tempval,1);
			iic_access(sdi_index,0x58,L0_CSR(port,i),&value,0);
			iic_access(sdi_index,0x58,L0_CSR(port,i),&tempval,1);

//			printf("tempval is %#x\n",tempval);

			if (value < 0x20 || (value > 0xFF && value < 0x303))
			{
//				printf("value valid.\n");
				if(tempval != value)
				{
					reg_address[count] = L0_CSR(port,i);
					destid_array[count] = i;
					count++;
				}
			}
			else
			{
				printf("value invalid\n");
				if(tempval != 0x300)
				{
					reg_address[count] = L0_CSR(port,i);
					destid_array[count] = i;
					count++;
				}
			}
		}
	}
	else if(level == 1)
	{
		for(i = 0;i < 256;i++)
		{
			iic_access(sdi_index,0x58,L1_CSR(port,group,i),&tempval,1);
			iic_access(sdi_index,0x58,L1_CSR(port,group,i),&value,0);
			iic_access(sdi_index,0x58,L1_CSR(port,group,i),&tempval,1);

//			printf("tempval is %#x\n",tempval);

			if (value < 0x20 || (value > 0xFF && value < 0x303))
			{
//				printf("value valid.\n");
				if(tempval != value)
				{
					reg_address[count] = L1_CSR(port,group,i);
					destid_array[count] = i;
					count++;
				}
			}
			else
			{
				printf("value invalid\n");
				if(tempval != 0x300)
				{
					reg_address[count] = L1_CSR(port,group,i);
					destid_array[count] = i;
					count++;
				}
			}
		}
	}
	else if(level == 2)
	{
		for(i = 0;i < 256;i++)
		{
			iic_access(sdi_index,0x58,L2_CSR(port,group,i),&tempval,1);
			iic_access(sdi_index,0x58,L2_CSR(port,group,i),&value,0);
			iic_access(sdi_index,0x58,L2_CSR(port,group,i),&tempval,1);

//			printf("tempval is %#x\n",tempval);

			if (value < 0x20 || (value > 0xFF && value < 0x200) || (value > 0x2FF && value < 0x303))
			{
//				printf("value valid.\n");
				if(tempval != value)
				{
					reg_address[count] = L2_CSR(port,group,i);
					destid_array[count] = i;
					count++;
				}
			}
			else
			{
				printf("value invalid\n");
				if(tempval != 0x300)
				{
					reg_address[count] = L2_CSR(port,group,i);
					destid_array[count] = i;
					count++;
				}
			}
		}
	}
	else if(level == 3)
	{
		for(i = 0;i < 256;i++)
		{
			iic_access(sdi_index,0x58,MC_S_CSR(port,i),&tempval1,1);
			iic_access(sdi_index,0x58,MC_S_CSR(port,i),&value,0);
			iic_access(sdi_index,0x58,MC_S_CSR(port,i),&tempval,1);
			
//			printf("tempval1 is %#x\n",tempval1);
//			printf("tempval is %#x\n",tempval);

			tempval1 = ((tempval1 & (~value)) | value);

//			printf("tempval1 is %#x\n",tempval1);

			if (tempval1 != tempval)
			{
					reg_address[count] = MC_S_CSR(port,i);
					destid_array[count] = i;
					count++;
			}
		}
	}
	else if(level == 4)
	{
		for(i = 0;i < 256;i++)
		{
			iic_access(sdi_index,0x58,MC_S_CSR(port,i),&group,0);
			iic_access(sdi_index,0x58,MC_CSR(port,i),&tempval1,1);
			iic_access(sdi_index,0x58,MC_CSR(port,i),&value,0);
			iic_access(sdi_index,0x58,MC_CSR(port,i),&tempval,1);
			
//			printf("tempval1 is %#x\n",tempval1);
//			printf("tempval is %#x\n",tempval);

			tempval1 = (tempval1 & (~value));
		
//			printf("tempval1 is %#x\n",tempval1);
//			printf("first input value is %#x , second input value %#x\n, result is %#x\n.",group,value,(group & (~value)));
			if (tempval1 != tempval)
			{
					reg_address[count] = MC_CSR(port,i);
					destid_array[count] = i;
					count++;
			}
		}
	}
	for(i = 0;i < count;i++)
	{
		printf("Error register offset is %#x, dest ID is %#X\n",reg_address[i],destid_array[i]);
	}
	return 0;

}

int higher2lower(char c)
{
	if(c >= 'A' && c <= 'Z')
		return c + 'a' - 'A';
	else
	  return c;
}

int htoi(char s[])
{
	int i;
	int n = 0;
	if(s[0] == '0' && (s[1] == 'x' || s[1] == 'x'))
	  i = 2;
	else
	  i = 0;
	for(;(s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'f') \
			|| (s[i] >= 'A' && s[i] <= 'F'); ++i)
	{
		if(higher2lower(s[i] > '9'))
		{
			n = 16 * n +(10 + higher2lower(s[i]) - 'a');
		}
		else
		  n = 16 * n + (higher2lower(s[i] - '0'));
	}
	return n;
}
